home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / alloc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-15  |  14.3 KB  |  606 lines

  1. /* memory allocation routines
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Adapted from alloc routine in K&R; memory statistics and interrupt
  5.  * protection added for use with net package. Must be used in place of
  6.  * standard Turbo-C library routines because the latter check for stack/heap
  7.  * collisions. This causes erroneous failures because process stacks are
  8.  * allocated off the heap.
  9.  *
  10.  * Mods by G1EMM , PA0GRI, KO4KS
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <dos.h>
  15. #include <alloc.h>
  16. #include "global.h"
  17. #include "config.h"
  18. #include "proc.h"
  19. #include "cmdparse.h"
  20. #include "mbuf.h"
  21.  
  22. static unsigned long Memfail;    /* Count of allocation failures */
  23. static unsigned long Allocs;    /* Total allocations */
  24. unsigned long Frees;    /* Total frees */
  25. static unsigned long Invalid;    /* Total calls to free with garbage arg */
  26. static unsigned long Yellows;    /* Yellow alert garbage collections */
  27. static unsigned long Reds;    /* Red alert garbage collections */
  28. static unsigned long Overuse;    /* Total calls to free with overused arg */
  29. static unsigned long Intalloc;    /* Calls to malloc with ints disabled */
  30. static unsigned long Intfree;    /* Calls to free with ints disabled */
  31. static int Memwait;        /* Number of tasks waiting for memory */
  32. static unsigned long Availmem;        /* Heap memory, ABLKSIZE units */
  33. static unsigned long ReallocSys;
  34. static unsigned long Morecores;
  35. #ifdef notdef
  36. static int Efficient = 1;    /* 0 = normal/fast, 1 = effecient/slow */
  37. #endif
  38. static int Memdebug = 0;    /* 0 = normal, 1 = call logstat() */
  39. #ifdef MULTITASK
  40. unsigned Minheap = 16 * 1024;    /* Min free heap when shelling out */
  41. #endif
  42. static char freewarn[] ="free: WARNING! %s (%Fp) pc = %04x:%04x proc %s%c";
  43. static char freewarn1[] = "invalid pointer";
  44. static char HeapSizeStr[] = "heap size %lu, avail %lu (%lu%%), morecores %lu (-%lu), coreleft %lu";
  45. static char AllocStr[] = "allocs %lu, frees %lu (diff %lu), alloc fails %lu, invalid frees %lu, overused %lu";
  46. static char GarbageStr[] = "garbage collections yellow %lu, red %lu";
  47. #ifdef notdef
  48. static char EfficientStr[] = "efficient %u, threshold %lu";
  49. #else
  50. static char EfficientStr[] = "threshold %lu";
  51. #endif
  52. static char InterruptStr[] = "interrupts-off calls to malloc %lu, free %lu\n";
  53. #ifdef Kelvdebug
  54. static char freewarn2[] = "overused buffer";
  55. #endif
  56.  
  57. extern void vmsstat();
  58. extern void displayStatLine __ARGS((int offset, int phase));
  59. extern char vgaDesired;
  60.  
  61. static unsigned long Sizes[16];
  62.  
  63. int logstat __ARGS((void));
  64.  
  65. static int dostat __ARGS((int argc,char *argv[],void *p));
  66. static int dofreelist __ARGS((int argc,char *argv[],void *p));
  67. static int doibufsize __ARGS((int argc,char *argv[],void *p));
  68. static int donibufs __ARGS((int argc,char *argv[],void *p));
  69. static int dothresh __ARGS((int argc,char *argv[],void *p));
  70. static int dosizes __ARGS((int argc,char *argv[],void *p));
  71. static int doefficient __ARGS((int argc,char *argv[],void *p));
  72. static int domemdebug __ARGS((int argc,char *argv[],void *p));
  73. static int dominheap __ARGS((int argc,char *argv[],void *p));
  74. static int dogcollect __ARGS((int argc,char *argv[],void *p));
  75.  
  76. struct cmds DFAR Memcmds[] = {
  77.     "debug",    domemdebug,    0, 0, NULLCHAR,
  78. #ifdef notdef
  79.     "efficient",    doefficient,    0, 0, NULLCHAR,
  80. #endif
  81.     "freelist",    dofreelist,    0, 0, NULLCHAR,
  82.     "gcollect",    dogcollect,    0, 0, NULLCHAR,
  83.     "ibufsize",    doibufsize,    0, 0, NULLCHAR,
  84. #ifdef MULTITASK
  85.     "minheap",  dominheap,  0, 0, NULLCHAR,
  86. #endif
  87.     "nibufs",   donibufs,   0, 0, NULLCHAR,
  88.     "sizes",    dosizes,    0, 0, NULLCHAR,
  89.     "status",    dostat,        0, 0, NULLCHAR,
  90.     "thresh",    dothresh,    0, 0, NULLCHAR,
  91.     NULLCHAR,
  92. };
  93.  
  94. #ifdef    LARGEDATA
  95. #define    HUGE    huge
  96. #else
  97. #define    HUGE
  98. #endif
  99.  
  100. union header {
  101.     struct {
  102.         union header HUGE *ptr;
  103.         unsigned long size;
  104.     } s;
  105.     long l[2];
  106. };
  107.  
  108. typedef union header HEADER;
  109. #define    NULLHDR    (HEADER HUGE *)NULL
  110.  
  111. #define    ABLKSIZE    (sizeof (HEADER))
  112.  
  113. static HEADER HUGE *morecore __ARGS((unsigned nu));
  114.  
  115. static HEADER Base;
  116. static HEADER HUGE *Allocp = NULLHDR;
  117. unsigned long Heapsize;
  118. static char HUGE *newbrk;
  119.  
  120. #ifdef Kelvdebug
  121. #define MARKER        0x766c654bL /* Kelv in reverse */
  122. #endif
  123.  
  124. /* Allocate block of 'nb' bytes */
  125. void *
  126. malloc(nb)
  127. unsigned nb;
  128. {
  129.     register HEADER HUGE *p, HUGE *q;
  130.     register unsigned nu;
  131.     int i;
  132.  
  133.     if(!istate())
  134.         Intalloc++;
  135.     if(nb == 0)
  136.         return NULL;
  137.  
  138.     /* Record the size of this request */
  139.     if((i = log2(nb)) >= 0)
  140.         Sizes[i]++;
  141.     
  142. #ifndef Kelvdebug
  143.      /* Round up to full block, then add one for header */
  144.  
  145.      nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 2;    /* force allocated memory  */
  146.     nu &= 0xfffffffeL;                /* to be on offset 0x0008 */
  147. #else
  148.      /* Round up to full block, then add one for header and one for debug */
  149.  
  150.      nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 4;    /* force allocated memory  */
  151.     nu &= 0xfffffffeL;                /* to be on offset 0x0008 */
  152. #endif
  153.  
  154.     if ((q = Allocp) == NULLHDR){
  155.         Base.s.ptr = Allocp = q = &Base;
  156.         Base.s.size = 1;
  157.     }
  158.  
  159. #ifdef notdef
  160.     if(Efficient) {
  161.         Allocp = q = &Base;    /* Start at the very beginning again */
  162.     }
  163. #endif
  164.  
  165.     for (p = q->s.ptr; ; q = p, p = p->s.ptr){
  166.         if (p->s.size >= nu){
  167.             /* This chunk is at least as large as we need */
  168.             if (p->s.size <= nu + 1){
  169.                 /* This is either a perfect fit (size == nu)
  170.                  * or the free chunk is just one unit larger.
  171.                  * In either case, alloc the whole thing,
  172.                  * because there's no point in keeping a free
  173.                  * block only large enough to hold the header.
  174.                  */
  175.                 q->s.ptr = p->s.ptr;
  176.             } else {
  177.                 /* Carve out piece from end of entry */
  178.                 p->s.size -= nu;
  179.                 p += p->s.size;
  180.                 p->s.size = nu;
  181.             }
  182.             p->s.ptr = p;    /* for auditing */
  183. #ifdef Kelvdebug
  184.              p->l[(p->s.size * 2) - 2] = (long)p;    /* debug */
  185.              p->l[(p->s.size * 2) - 1] = MARKER;    /* debug */
  186. #endif
  187.             Allocs++;
  188.             Availmem -= p->s.size;
  189.             p++;
  190. #ifdef    LARGEDATA
  191.             /* On the brain-damaged Intel CPUs in
  192.              * "large data" model, make sure the offset field
  193.              * in the pointer we return isn't null.
  194.              * The Turbo C compiler and certain
  195.              * library functions like strrchr() assume this.
  196.              */
  197.             if(FP_OFF(p) == 0){
  198.                 /* Return denormalized but equivalent pointer */
  199.                 return (void *)MK_FP(FP_SEG(p)-1,16);
  200.             }
  201. #endif
  202.             return (void *)p;
  203.         }
  204.         if (p == Allocp && ((p = morecore(nu)) == NULLHDR)){
  205.             Memfail++;
  206.             return NULL;
  207.         }
  208.     }
  209. }
  210. /* Get more memory from the system and put it on the heap */
  211. static HEADER HUGE *
  212. morecore(nu)
  213. unsigned nu;
  214. {
  215. register HEADER HUGE *up;
  216.  
  217.     Morecores++;
  218.     if ((int)(newbrk = (char HUGE *)sbrk(nu * ABLKSIZE)) == -1){
  219.         if (Memdebug)    {
  220.             log(-1,"morecore: Failure requesting %ul (coreleft %ul)",
  221.                 (unsigned long) nu * ABLKSIZE,(unsigned long) coreleft());
  222.             logstat();
  223.         }
  224.         return NULLHDR;
  225.     }
  226.  
  227.     up = (HEADER *)newbrk;
  228.     newbrk += (nu * ABLKSIZE);
  229.     up->s.size = nu;
  230.     up->s.ptr = up;    /* satisfy audit */
  231. #ifdef Kelvdebug
  232.      up->l[(up->s.size * 2) - 2] = (long)up;        /* satisfy debug */
  233.      up->l[(up->s.size * 2) - 1] = MARKER;        /* satisfy debug */
  234. #endif
  235.     free((void *)(up + 1));
  236.     Heapsize += nu*ABLKSIZE;
  237.     Frees--;    /* Nullify increment inside free() */
  238.     return Allocp;
  239. }
  240.  
  241. extern void stktrace();
  242.  
  243. /* Put memory block back on heap */
  244. void
  245. free(blk)
  246. void *blk;
  247. {
  248.     register HEADER HUGE *p, HUGE *q;
  249.     unsigned short HUGE *ptr;
  250.  
  251.     if(!istate())
  252.         Intfree++;
  253.     if(blk == NULL)
  254.         return;        /* Required by ANSI */
  255.     p = (HEADER HUGE *)blk - 1;
  256.     /* Audit check */
  257.     if(p->s.ptr != p){
  258.         ptr = (unsigned short *)&blk;
  259.         printf(freewarn,freewarn1,blk,ptr[-1],ptr[-2],Curproc->name,'\n');
  260.         fflush(stdout);
  261. #ifdef STKTRACE
  262.         stktrace();
  263. #endif
  264.         Invalid++;
  265.         log(-1,freewarn,freewarn1,blk,ptr[-1],ptr[-2],Curproc->name,' ');
  266.         logstat();
  267.         return;
  268.     }
  269. #ifdef Kelvdebug
  270.      if(p->l[(p->s.size * 2) - 2] != (long)p || p->l[(p->s.size * 2) - 1] != MARKER){
  271.          ptr = (unsigned short *)&blk;
  272.         printf(freewarn,freewarn2,blk,ptr[-1],ptr[-2],Curproc->name,'\n');
  273.         fflush(stdout);
  274.          Overuse++;
  275.         log(-1,freewarn,freewarn2,blk,ptr[-1],ptr[-2],Curproc->name,' ');
  276.         logstat();
  277.          return;
  278.      }
  279. #endif
  280.     Availmem += p->s.size;
  281.     /* Search the free list looking for the right place to insert */
  282.     for(q = Allocp; !(p > q && p < q->s.ptr); q = q->s.ptr){
  283.         /* Highest address on circular list? */
  284.         if(q >= q->s.ptr && (p > q || p < q->s.ptr))
  285.             break;
  286.     }
  287.     if(p + p->s.size == q->s.ptr){
  288.         /* Combine with front of this entry */
  289.         p->s.size += q->s.ptr->s.size;
  290.         p->s.ptr = q->s.ptr->s.ptr;
  291.     } else {
  292.         /* Link to front of this entry */
  293.         p->s.ptr = q->s.ptr;
  294.     }
  295.     if(q + q->s.size == p){
  296.         /* Combine with end of this entry */
  297.         q->s.size += p->s.size;
  298.         q->s.ptr = p->s.ptr;
  299.     } else {
  300.         /* Link to end of this entry */
  301.         q->s.ptr = p;
  302.     }
  303.  
  304.     Frees++;
  305.     if(Memwait != 0)
  306.         psignal(&Memwait,0);
  307. }
  308.  
  309. #ifdef    notdef    /* Not presently used */
  310. /* Move existing block to new area */
  311. void *
  312. realloc(area,size)
  313. void *area;
  314. unsigned size;
  315. {
  316.     unsigned osize;
  317.     HEADER HUGE *hp;
  318.     char HUGE *cp;
  319.  
  320.     hp = ((HEADER *)area) - 1;
  321.     osize = (hp->s.size -1) * ABLKSIZE;
  322.  
  323.     free(area);    /* Hopefully you have your interrupts off , Phil. */
  324.     if((cp = malloc(size)) != NULL && cp != area)
  325.         memcpy((char *)cp,(char *)area,size>osize? osize : size);
  326.     return cp;
  327. }
  328. #endif
  329. /* Allocate block of cleared memory */
  330. void *
  331. calloc(nelem,size)
  332. unsigned nelem;    /* Number of elements */
  333. unsigned size;    /* Size of each element */
  334. {
  335.     register unsigned i;
  336.     register char *cp;
  337.  
  338.     i = nelem * size;
  339.     if((cp = malloc(i)) != NULL)
  340.         memset(cp,0,i);
  341.     return cp;
  342. }
  343. /* Version of malloc() that waits if necessary for memory to become available */
  344. void *
  345. mallocw(nb)
  346. unsigned nb;
  347. {
  348.     register void *p;
  349.  
  350.     while((p = malloc(nb)) == NULL){
  351.         Memwait++;
  352.         pwait(&Memwait);
  353.         Memwait--;
  354.     }
  355.     return p;
  356. }
  357. /* Version of calloc that waits if necessary for memory to become available */
  358. void *
  359. callocw(nelem,size)
  360. unsigned nelem;    /* Number of elements */
  361. unsigned size;    /* Size of each element */
  362. {
  363.     register unsigned i;
  364.     register char *cp;
  365.  
  366.     i = nelem * size;
  367.     cp = mallocw(i);
  368.     memset(cp,0,i);
  369.     return cp;
  370. }
  371. /* Return available memory on our heap plus available system memory */
  372. unsigned long
  373. availmem()
  374. {
  375.     return Availmem * ABLKSIZE + coreleft();
  376. }
  377.  
  378. /* Log heap stats */
  379. int
  380. logstat()
  381. {
  382.     if(Memdebug){
  383.         log(-1,"Memory status :");
  384.         log(-1,HeapSizeStr,Heapsize,Availmem*ABLKSIZE, \
  385.             100L*Availmem*ABLKSIZE/Heapsize,Morecores,ReallocSys,coreleft());
  386.         log(-1,AllocStr,Allocs,Frees,Allocs-Frees,Memfail,Invalid,Overuse);
  387.         log(-1,GarbageStr,Yellows,Reds);
  388. #ifdef notdef
  389.         log(-1,EfficientStr,Efficient,Memthresh);
  390. #else
  391.         log(-1,EfficientStr,Memthresh);
  392. #endif
  393.         log(-1,InterruptStr,Intalloc,Intfree);
  394.     }
  395.  
  396.     return 0;
  397. }
  398.  
  399. void
  400. mbmemory ()
  401. {
  402.     tprintf(HeapSizeStr,Heapsize,Availmem*ABLKSIZE, \
  403.             100L*Availmem*ABLKSIZE/Heapsize,Morecores,ReallocSys,coreleft());
  404.     tputc('\n');
  405. }
  406.  
  407.  
  408. /* Print heap stats */
  409. static int
  410. dostat(argc,argv,envp)
  411. int argc;
  412. char *argv[];
  413. void *envp;
  414. {
  415.     mbmemory();
  416.     tprintf(AllocStr,Allocs,Frees,Allocs-Frees,Memfail,Invalid,Overuse);
  417.     tputc('\n');
  418.     tprintf(GarbageStr,Yellows,Reds);
  419.     tputc('\n');
  420.     tprintf(InterruptStr,Intalloc,Intfree);
  421.         vmsstat();
  422.     iqstat();
  423.     return 0;
  424. }
  425.  
  426. /* Print heap free list */
  427. static int
  428. dofreelist(argc,argv,envp)
  429. int argc;
  430. char *argv[];
  431. void *envp;
  432. {
  433.     HEADER HUGE *p;
  434.     int i = 0;
  435.  
  436.     for(p = Base.s.ptr;p != &Base;p = p->s.ptr){
  437.         tprintf("%4.4x %6lu",FP_SEG(p),p->s.size * ABLKSIZE);
  438.         if(++i == 5){
  439.             i = 0;
  440.             if(tprintf("\n") == EOF)
  441.                 return 0;
  442.         } else
  443.             tprintf(" | ");
  444.     }
  445.     if(i != 0)
  446.         tprintf("\n");
  447.     return 0;
  448. }
  449. static int
  450. dosizes(argc,argv,p)
  451. int argc;
  452. char *argv[];
  453. void *p;
  454. {
  455.     int i;
  456.  
  457.     for(i=0;i<16;i += 4){
  458.         tprintf("N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld\n",
  459.          1<<i,Sizes[i],    2<<i,Sizes[i+1],
  460.          4<<i,Sizes[i+2],8<<i,Sizes[i+3]);
  461.     }
  462.     return 0;
  463. }
  464. int
  465. domem(argc,argv,p)
  466. int argc;
  467. char *argv[];
  468. void *p;
  469. {
  470.     return subcmd(Memcmds,argc,argv,p);
  471. }
  472.  
  473. static int
  474. dothresh(argc,argv,p)
  475. int argc;
  476. char *argv[];
  477. void *p;
  478. {
  479.     return setlong(&Memthresh,"Free memory threshold (bytes)",argc,argv);
  480. }
  481.  
  482. static int
  483. donibufs(argc,argv,p)
  484. int argc;
  485. char *argv[];
  486. void *p;
  487. {
  488.     if(setint(&Nibufs,"Interrupt pool buffers",argc,argv) == 0){
  489.         iqclear();
  490.         return 0;
  491.     }
  492.     return 1;
  493. }
  494. static int
  495. doibufsize(argc,argv,p)
  496. int argc;
  497. char *argv[];
  498. void *p;
  499. {
  500.     return setuns(&Ibufsize,"Interrupt buffer size",argc,argv);
  501. }
  502.  
  503. static int
  504. dogcollect(argc,argv,p)
  505. int argc;
  506. char *argv[];
  507. void *p;
  508. {
  509. void (**fp)();
  510.  
  511.     Yellows++;
  512.     for(fp = Gcollect;*fp != NULL;fp++)
  513.         (**fp)(0);
  514.     tputs ("Garbage collection forced at Yellow level!\n");
  515.     return 0;
  516. }
  517.  
  518.  
  519. void
  520. gcollect(i,v1,v2)
  521. int i;        /* Args not used */
  522. char *v1;
  523. void *v2;
  524. {
  525. void (**fp)();
  526. int red;
  527. HEADER HUGE *p, *last;
  528. char HUGE *calc;
  529. unsigned long backto, backcnt;
  530. int backed;
  531.  
  532.     for(;;){
  533.         mspause(500L);    /* Run displayStatLine every 1/2 second */
  534.         displayStatLine (0, 1);
  535.         mspause(500L);    /* and run the rest every second */
  536.         displayStatLine (0, 0);
  537. #ifdef SCREENSAVER
  538.         screensaver ();
  539. #endif
  540.         /* If memory is low, collect some garbage. If memory is VERY
  541.          * low, invoke the garbage collection routines in "red" mode.
  542.          */
  543.         if(availmem() < Memthresh){
  544.             if(availmem() < Memthresh/2){
  545.                 red = 1;
  546.                 Reds++;
  547.             } else {
  548.                 red = 0;
  549.                 Yellows++;
  550.             }
  551.             for(fp = Gcollect;*fp != NULL;fp++)
  552.                 (**fp)(red);
  553.         }
  554.         last = 0;
  555.         for (p = Base.s.ptr; p->s.ptr != &Base; p = p->s.ptr)
  556.             last = p;
  557.         if (!last)
  558.             continue;
  559.         calc = (char HUGE *)(p + p->s.size);
  560.         if (newbrk <= calc)        {
  561.             backcnt = backto = (p->s.size * ABLKSIZE);
  562.             do    {
  563.                 backed = (backcnt < 32767) ? backcnt : 32767;
  564.                 sbrk (-1 * backed);
  565.                 backcnt -= backed;
  566.             } while (backcnt);
  567.             newbrk -= backto;
  568.             Heapsize -= backto;
  569.             Availmem -= p->s.size;
  570.             last->s.ptr = &Base;
  571.             ReallocSys++;
  572.         }
  573.     }
  574. }
  575.  
  576. #ifdef notdef
  577. static int
  578. doefficient(argc,argv,p)
  579. int argc;
  580. char *argv[];
  581. void *p;
  582. {
  583.     return setbool(&Efficient,"Efficient/slower mode",argc,argv);
  584. }
  585. #endif
  586.  
  587. static int
  588. domemdebug(argc,argv,p)
  589. int argc;
  590. char *argv[];
  591. void *p;
  592. {
  593.     return setbool(&Memdebug,"\"Mem stat\" to log after failures",argc,argv);
  594. }
  595.  
  596. #ifdef MULTITASK
  597. static int
  598. dominheap(argc,argv,p)
  599. int argc;
  600. char *argv[];
  601. void *p;
  602. {
  603.     return setuns(&Minheap,"Minimum free heap when shelled out",argc,argv);
  604. }
  605. #endif
  606.